package tenet.util;

import java.util.Random;

/**
 * Thrown when an assertion fails.
 */
class AssertionFailureError extends Error {
	/**
	 * serial version UID
	 */
	private static final long serialVersionUID = 1L;

	AssertionFailureError() {
		super();
	}

	AssertionFailureError(String message) {
		super(message);
	}
}

/**
 * Lib
 * 
 * @date 2011/12/1
 * @author drf
 *
 */
public class Lib {
	/**
	 * Print <i>message</i> if <i>flag</i> was enabled on the command line. To
	 * specify which flags to enable, use the -d command line option. For
	 * example, to enable flags a, c, and e, do the following:
	 * 
	 * <p>
	 * 
	 * <pre>
	 * DnsClient -d ace
	 * </pre>
	 * 
	 * <p>
	 * DNS uses several debugging flags for the project.
	 * 
	 * @param flag
	 *            the debug flag that must be set to print this message.
	 * @param message
	 *            the debug message.
	 */
	private static void printFlag(char flag) {
		if (flag == flagARP) 
			System.out.print("ARP   : "); else
		if (flag == flagL2)
			System.out.print("L2    : "); else
		if (flag == flagStoreForward)
			System.out.print("Store : "); else
		if (flag == flagDatalink)
			System.out.print("Data : "); else
		if (flag == flagL2)
			System.out.print("Temp  : ");
	}
	
	private static void printKeyFlag(char flag) {
		System.out.print("*"); 
		printFlag(flag); 
	}
	
	public static void debug(char flag, String message) {
		if (test(flag)) {
			System.out.print(" "); 
			printFlag(flag);
			System.out.println(message);
		}
	}
	
	public static void debug(char flag, String message, boolean key) {
		if (test(flag)) {
			System.out.print(" "); 
			if (key == true) printKeyFlag(flag);
			System.out.println(message);
		}
	}
	
	public static void debugsp(char flag) {
		if (test(flag))
			System.out.println("==========================================================");
	}
	
	public static void debugsq(char flag) {
		if (test(flag))
			System.out.println("----------------------------------------------------------");
	}
	
	/**
	 * Tests if <i>flag</i> was enabled on the command line.
	 * 
	 * @param flag
	 *            the debug flag to test.
	 * 
	 * @return <tt>true</tt> if this flag was enabled on the command line.
	 */
	public static boolean test(char flag) {
		if (debugFlags == null)
			return false;
		else if (debugFlags[(int) '+'])
			return true;
		else if (flag >= 0 && flag < 0x80 && debugFlags[(int) flag])
			return true;
		else
			return false;
	}

	/**
	 * Test if a bit is set in a bit string.
	 * 
	 * @param flag
	 *            the flag to test.
	 * @param bits
	 *            the bit string.
	 * @return <tt>true</tt> if <tt>(bits & flag)</tt> is non-zero.
	 */
	public static boolean test(long flag, long bits) {
		return ((bits & flag) != 0);
	}
	
	/**
	 * Enable all the debug flags in <i>flagsString</i>.
	 * 
	 * @param flagsString
	 *            the flags to enable.
	 */
	public static void enableDebugFlags(String flagsString) {
		if (debugFlags == null)
			debugFlags = new boolean[0x80];

		char[] newFlags = flagsString.toCharArray();
		for (int i = 0; i < newFlags.length; i++) {
			char c = newFlags[i];
			if (c >= 0 && c < 0x80)
				debugFlags[(int) c] = true;
		}
	}


	/**
	 * Return an array containing all command line arguments.
	 * 
	 * @return the command line arguments passed to DNS.
	 */
	public static String[] getCommandLineArguments() {
		String[] result = new String[args.length];

		System.arraycopy(args, 0, result, 0, args.length);

		return result;
	}
	
	/**
	 * Asserts that <i>expression</i> is <tt>true</tt>. If not, then DNS
	 * exits with the specified error message.
	 * 
	 * @param expression
	 *            the expression to assert.
	 * @param message
	 *            the error message.
	 */
	public static void assertTrue(boolean expression, String message) {
		if (!expression)
			throw new AssertionFailureError(message);
	}
	

	/**
	 * Asserts that <i>expression</i> is <tt>true</tt>.
	 * If not, then DNS exits with an error message.
	 * 
	 * @param expression
	 *            the expression to assert.
	 */
	public static void assertTrue(boolean expression) {
		if (!expression)
			throw new AssertionFailureError();
	}
	
	public static void processArgs(String[] args) {
		for (int i = 0; i < args.length;) {
			String arg = args[i++];
			if (arg.length() > 0 && arg.charAt(0) == '-') {
				if (arg.equals("-d")) {
					assertTrue(i < args.length, "switch without argument");
					enableDebugFlags(args[i++]);
				} else if (arg.equals("-[]")) {
					assertTrue(i < args.length, "switch without argument");
					configFileName = args[i++];
				} 
			}
		}
	}

	private static Random random = null;

	/**
	 * Seed the random number generater. May only be called once.
	 * 
	 * @param randomSeed
	 *            the seed for the random number generator.
	 */
	public static void seedRandom(long randomSeed) {
		assertTrue(random == null);
		random = new Random(randomSeed);
	}

	/**
	 * Return a random integer between 0 and <i>range - 1</i>. Must not be
	 * called before <tt>seedRandom()</tt> seeds the random number generator.
	 * 
	 * @param range
	 *            a positive value specifying the number of possible return
	 *            values.
	 * @return a random integer in the specified range.
	 */
	public static int random(int range) {
		assertTrue(range > 0);
		return random.nextInt(range);
	}

	/**
	 * Return a random double between 0.0 (inclusive) and 1.0 (exclusive).
	 * 
	 * @return a random double between 0.0 and 1.0.
	 */
	public static double random() {
		return random.nextDouble();
	}

	public static String getErrorMsg() {
		return errorMsg;
	}
	
	public static String getErrorARP() {
		return errorARP;
	}
	
	public static String getErrorL2() {
		return errorL2;
	}
	/**
	 * 
	 */
	/** Debug flags specified on the command line. */
	private static boolean debugFlags[];
	
	private static String configFileName = "dns.conf";
	private static String errorMsg = "Error";
	private static String errorARP = "ARP error"; 
	private static String errorL2 = "L2 switch error"; 
	
	private static String[] args = null;
	
	/** Default port numbers **/
	public static final String localhost = "127.0.0.1"; 
	
	/** Debug flags for our system **/ //dlast
	public static char flagARP = 'a'; 
	public static char flagL2 = 'l'; 
	public static char flagStoreForward = 's'; 
	public static char flagDatalink = 'd';
	public static char flagTemp = 't'; 
}
